﻿using Server.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Server
{

    struct MSystem
    {
        public object Instance;
        public Action Start;
        public Action Update;

        public MSystem(object instance, Action start, Action update)
        {
            Instance = instance;
            Start = start;
            Update = update;
        }
    }

    class MySystem
    {
        public static readonly string INITIALIZE = "Init";
        public static readonly string START = "Start";
        public static readonly string UPDATE = "Update";

        readonly static Dictionary<Type, MSystem> _Systems = new();

        readonly static Dictionary<Type, object> Systems = new();

        static Action[] Updates;

        static bool _isStart;
        static bool _isInit;

        public static T GetSystem<T>() where T : class
        {
            if (!_isInit)
            {
                Console.WriteLine($"====== GetSystem Haven't Init !!!");
                return null;
            }

            if (Systems.TryGetValue(typeof(T), out object sys))
            {
                return sys as T;
            }
            else
            {
                Console.WriteLine($"====== TryGetValue Fail !!!");
                return null;
            }
        }

        public static void Start()
        {
            _Systems.Clear();
            Systems.Clear();

            foreach (var type in CommolOption.GetAttributeTypes<SystemAttribute>(typeof(MySystem).Assembly))
            {
                MSystem sys = new();
                sys.Instance = Activator.CreateInstance(type);

                if (CommolOption.TryCreateDelegate(sys.Instance, INITIALIZE, out Action init))
                {
                    init.Invoke();
                }
                if (CommolOption.TryCreateDelegate(sys.Instance, START, out Action start))
                {
                    sys.Start = start;
                }
                if (CommolOption.TryCreateDelegate(sys.Instance, UPDATE, out Action update))
                {
                    sys.Update = update;
                }

                _Systems.Add(type, sys);
                Systems.Add(type, sys.Instance);
            }

            _isInit = true;

            List<Action> updates = new();
            foreach (var sys in _Systems.Values)
            {
                sys.Start?.Invoke();

                if (sys.Update != null)
                {
                    updates.Add(sys.Update);
                    sys.Update.Invoke();
                }

                Console.WriteLine($"====== {sys.Instance.GetType().Name} Start !!!");
            }

            Updates = updates.ToArray();

            _isStart = true;
        }

        public static void Update()
        {

            if (!_isStart)
            {
                Console.WriteLine($"====== Haven't Start !!!");
                return;
            }

            for (int i = 0; i < Updates.Length; i++)
            {
                Updates[i].Invoke();
            }

        }

        public static void Stop()
        {
            _isStart = false;
            _isInit = false;
        }

    }
}
